[WIP] Introduce aarch64-unknown-linux-pauthtest target#154759
[WIP] Introduce aarch64-unknown-linux-pauthtest target#154759jchlanda wants to merge 46 commits intorust-lang:mainfrom
Conversation
This comment has been minimized.
This comment has been minimized.
88b623e to
3b3fcce
Compare
This comment has been minimized.
This comment has been minimized.
3b3fcce to
e33dbf3
Compare
This comment has been minimized.
This comment has been minimized.
e33dbf3 to
9e48aaa
Compare
This comment has been minimized.
This comment has been minimized.
9e48aaa to
4468c36
Compare
This comment has been minimized.
This comment has been minimized.
4468c36 to
c9fe7d6
Compare
This comment has been minimized.
This comment has been minimized.
c9fe7d6 to
7ecdaa6
Compare
This comment has been minimized.
This comment has been minimized.
7ecdaa6 to
65007e0
Compare
This comment has been minimized.
This comment has been minimized.
65007e0 to
566b1b6
Compare
This comment has been minimized.
This comment has been minimized.
0db30a1 to
5bc3e48
Compare
This comment has been minimized.
This comment has been minimized.
| if (!C) | ||
| return Ptr; | ||
| if (!C->getType()->isPointerTy()) | ||
| return Ptr; | ||
| if (isa<UndefValue>(C) || isa<ConstantPointerNull>(C)) | ||
| return Ptr; |
There was a problem hiding this comment.
Do we expect values non-conforming to these conditions being passed to this function? Locally, I've commented out these lines, and nothing seems to be broken.
So, can we safely convert these to assertions? Or, maybe, some checks which would be present in release mode as well (and would panic when mismatch is detected)? Please just explain which contract do we have, who is responsible for these checks and whether the checks need to be just assertions or if we need to make them panicking or smth.
If there's a reason why we need to keep the current behavior, it's totally fine. But if so, can we somehow rename the function? Now it's name might make one think that we always wrap the underlying constant pointer value to ptrauth constant. But we also have this chunk of logic returning the exact input value w/o any change, and this is not clear from the function name.
There was a problem hiding this comment.
Fair.
With it now being wrapped in const_ptr_auth and only two call sites we can't violate the contract.
However it is still a symbol that can be accessed freely. I'm going to change it to asserts.
There was a problem hiding this comment.
Thanks! Just in case it was already intended to be changed to asserts - the checks are still present and nothing was changed. Are you about to submit this update or was there a reason why we want to keep the actual checks?
There was a problem hiding this comment.
Apologies, this was in an unsaved buffer in my editor. Done now.
This comment has been minimized.
This comment has been minimized.
Looks like there is no bug in there, it's an expected behaviour. I'm guessing that when you compiled for You can verify that by either changing the arch to Will disable the test and add a comment. |
What I'm worried about is that in compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_pauthtest.rs we have And my understanding was that if we add |
This comment has been minimized.
This comment has been minimized.
6ee8cab to
9f2ac73
Compare
There was a problem hiding this comment.
@jchlanda Regarding test failures you've mentioned today - it looks like that for tests we need to manually specify additional compile args, otherwise stage1-tools-bin/compiletest uses the defaults.
Particularly, when running ./x test, it looks like we need to add --test-args --target-rustcflags --test-args "-Clink-arg=-Wl,--dynamic-linker=/path/to/aarch64-unknown-linux-pauthtest/usr/lib/libc.so".
This way of handling the issue is described in src/doc/rustc/src/platform-support/fuchsia.md
Thank you @kovdan01. This indeed helps with a group of tests, but, still when we are in subprocess scenarios I see failures. I'll DM you. |
| // authentication features is currently supported. By default, the absence of this | ||
| // info is treated as compatible with any binary. | ||
| // | ||
| // Please note, that this would cause compatibility issues when linking against |
There was a problem hiding this comment.
I suppose it's worth rephrasing this highlighting the following details:
- When talking about "compatibility issues", we are talking about runtime crashes due to auth failures while silently compiling and linking w/o problems
- I would not generalize this to "fully pauth-enabled c/c++ binaries". We are OK with interop when only pointers signed using supported ptrauth feature subset are crossing c/rust boundary (at this point, meaning only free function pointers signed w/o type discrimination). So we need to highlight that if pointers signed with other features cross c/rust or cxx/rust boundary, we result in runtime failures. Maybe even provide a list of such pointers: member function pointers, virtual function pointers, virtual table pointers, maybe smth else I forgot to mention (free function pointers with non-zero discr are technically not a part of pauthtest ABI, so not mentioning here)
There was a problem hiding this comment.
OK, tried to incorporate this.
There was a problem hiding this comment.
// (for example member function pointers, virtual function pointers, virtual table
// pointers).
Probably "for example, signing of C++ member ..."
| * the call is performed indirectly via a signed pointer, | ||
| * the `ptrauth` operand bundle enforces authentication at call time. | ||
|
|
||
| ## Cross-compilation |
There was a problem hiding this comment.
There are no other targets which define both "Cross-compilation" and "Cross-compilation toolchains and C code" sections. Probably we should stick to the TEMPLATE.md and only leave the latter section, moving contents from here if needed.
There was a problem hiding this comment.
OK, renamed Cross-compilation to Cross-compilation toolchains and C code and brought the content of the latter to the former.
| must be consistent across Rust and C components. The target only supports | ||
| dynamic linking with the custom interpreter. | ||
|
|
||
| ## Limitation |
There was a problem hiding this comment.
Nit: probably an empty line after this would make things more consistent across the file
|
|
||
| * `src/main.rs` | ||
|
|
||
| ```rust,ignore (rustc will have no core crate for pauthtest) |
There was a problem hiding this comment.
What does this ignore (rustc will have no core crate for pauthtest) mean and which purpose does it serve?
There was a problem hiding this comment.
Rust has this tool called doctest. In CI it parses all documents (md files) and picks up on code blocks. It then tries to produce a fully linked executable from that extracted code. I've slightly changed the snippet to: use std::ptr, so it doesn't rely on the core. But even so, the use of external function will trip the linker up. Hence the use of ignore. I've also change the message to (platform-specific) as that seems to be the convention in such cases.
|
|
||
| * `build.rs` | ||
|
|
||
| ```rust,no_run |
There was a problem hiding this comment.
What does no_run mean? I'm just not very familiar with this stuff, my understanding was it's just used for syntax highlighting
There was a problem hiding this comment.
Same as above, rustdoc will not be able to handle the Command::new(clang). Also changed to ignore (platform-specific) for consistency.
| ```toml | ||
| [package] | ||
| name = "rust_c_indirect" | ||
| version = "0.1.0" |
There was a problem hiding this comment.
As far as I understand from rust docs, version and edition are not mandatory. Could these be removed?
There was a problem hiding this comment.
You are right, but the lack of edition will result in a warning:
warning: no edition set: defaulting to the 2015 edition while the latest is 2024
I'm going to leave the edition in, and while at it, bump it to 2024.
Removing version.
| must be compiled with the pauthtest aware compiler. Mixed Rust/C programs are | ||
| supported and tested (e.g. quicksort examples). Pointer authentication semantics | ||
| must be consistent across Rust and C components. The target only supports | ||
| dynamic linking with the custom interpreter. |
There was a problem hiding this comment.
I suppose that info about support only for dynamic linking should be somewhere in the overall target description, probably close to the top of the document - it's not cross-compilation specific, it's just a very important piece of info.
And I would also not say "custom interpreter" - it's not clear what does it mean. Maybe smth like "... dynamic linking with a pauthtest-enabled dynamic linker serving as ELF interpreter capable of resolving pauth relocations and respecting pauthtest ABI nuances" (maybe it could be somehow rephrased shorter, I'm just trying to make it clear which kind of "custom" dynamic loader we need)
There was a problem hiding this comment.
OK. Leaving "The target only supports dynamic linking." here, and reworded the opening paragraph to use your suggestion. It seems like a right spot for it.
| must be consistent across Rust and C components. The target only supports | ||
| dynamic linking with the custom interpreter. | ||
|
|
||
| ## Limitation |
There was a problem hiding this comment.
It's probably worth to make this plural, not singular, and add info about C++ interop and other currently unsupported pauthtest ABI features. It looks like that from the current version of the doc it's not very clear that these would be "by design" broken with runtime auth failures.
| named for convenience): | ||
|
|
||
| ```sh | ||
| x.py test --target aarch64-unknown-linux-pauthtest --force-rerun \ |
There was a problem hiding this comment.
Does it work this way or do we need to add --test-arg ... stuff I've mentioned previously in my comments to make rust test runner propagate correct dyn linker for rustc calls?
There was a problem hiding this comment.
Without, after extending the wrapper script to have:
-Wl,--dynamic-linker=<toolchain_root>/aarch64-linux-pauthtest/usr/lib/libc.so \
-Wl,--rpath=<toolchain_root>/aarch64-linux-pauthtest/usr/lib \
the test can be run with:
x.py test --target aarch64-unknown-linux-pauthtest ...
| * UI error reporting (pauthtest does not support `+crt-static`) | ||
| * crt-static-pauthtest.rs | ||
|
|
||
| All tests from `assembly-llvm`, `codegen-llvm`, `codegen-units`, `coverage`, |
There was a problem hiding this comment.
Is library (core, alloc, std) missed here?
| The following categories are supported (all present in tree): | ||
| * Assembly tests | ||
| * targets-aarch64_unknown_linux_pauthtest.rs | ||
| * LLVM IR/codegen tests |
There was a problem hiding this comment.
The extern-weak test looks missing in this list
| * UI error reporting (pauthtest does not support `+crt-static`) | ||
| * crt-static-pauthtest.rs | ||
|
|
||
| All tests from `assembly-llvm`, `codegen-llvm`, `codegen-units`, `coverage`, |
There was a problem hiding this comment.
Thanks for mentioning extra coverage here! BTW, it actually looks like that while some test suites like mir-opt, incremental, crashes indeed execute for the pauthtest target, some other ones are not (at least for me some suites show things like Testing stage1 with compiletest suite=XXX mode=XXX (x86_64-unknown-linux-gnu)
These are the suites which seem to only be tested against host (even though I'm running ./x test with explicit pauthtest target specified):
- coverage-run-rustdoc
- pretty
- rustdoc-html
- rustdoc-js
- rustdoc-js-std
- rustdoc-json
- rustdoc-ui
- ui-fulldeps
I might be running tests somehow incorrectly and maybe you actually observe them really running and passing for the pauthtest target. But if not and they only run for the host target - worth excluding from the list
There was a problem hiding this comment.
No, that is what I saw on my system as well. I wasn't sure about those, we pass the target to the x runner and it is its decision how to treat them.
Removing now, maybe it is just noise.
| // authentication features is currently supported. By default, the absence of this | ||
| // info is treated as compatible with any binary. | ||
| // | ||
| // Please note, that this would cause compatibility issues when linking against |
There was a problem hiding this comment.
// (for example member function pointers, virtual function pointers, virtual table
// pointers).
Probably "for example, signing of C++ member ..."
|
|
||
| #[inline] | ||
| pub(crate) fn pauth_fn_attrs() -> &'static [&'static str] { | ||
| // FIXME(jchlanda) This is not an exhaustive list of all `pauthtest`-related attributes, but |
There was a problem hiding this comment.
| // FIXME(jchlanda) This is not an exhaustive list of all `pauthtest`-related attributes, but | |
| // FIXME(jchlanda) This is not an exhaustive list of all `ptrauth`-related attributes, but |
| let address_space = cx.tcx.global_alloc(prov.alloc_id()).address_space(cx); | ||
|
|
||
| llvals.push(cx.scalar_to_backend( | ||
| // For aarch64-unknown-linux-pauthtest function pointers stored in init/fini arrays need |
There was a problem hiding this comment.
I'd rather say something like "Under pointer authentication function pointers stored in init/fini arrays need special handling"
View all comments
The target enables Pointer Authentication Code (PAC) support in Rust on AArch64
ELF based Linux systems using a pauthtest ABI (provided by LLVM) and
pauthtest-enabled sysroot with custom musl, serving as a reference libc
implementation. It requires dynamic linking with a pauthtest-enabled dynamic
linker serving as ELF interpreter capable of resolving pauth relocations and
respecting pauthtest ABI constraints.
Supported features include:
(corresponds to
-fptrauth-callsincluded in pauthtest ABI as defined inLLVM)
address after restoring from stack for non-leaf functions (corresponds to
-fptrauth-returns)(corresponds to
-fptrauth-auth-traps)ABI (corresponding to
-fptrauth-init-fini,-fptrauth-init-fini-address-discrimination)pauthtest ABI (corresponding to
-faarch64-jump-table-hardening,-fptrauth-indirect-gotos)-Z ptrauth-elf-got, off by default)Existing compiler support, such as enabling branch authentication instructions
(i.e.:
-Z branch-protection) provide limited functionality, mainly signingreturn addresses (
pac-ret). The new target goes further by enabling ABI-levelpointer authentication support.
Please note that efforts were made to split the work into individual commits
that encapsulate different areas of the code; however, the commits are not
atomic and cannot be built or tested in isolation.
Useful links: